<template>
    <div class="hls-video">
        <video ref="videoRef" :controls="controls" @loadeddata="log" @loadedmetadata="log" @canplay="log"
               @canplaythrough="log" @play="log" @playing="log" @waiting="log" @seeking="log" @seeked="log"
               @timeupdate="log" @pause="log" @ended="log" @ratechange="log" @durationchange="log" @volumechange="log"
               @suspend="log" @emptied="log" @stalled="log" @error="log" playsinline :muted="muted"></video>
        <div class="absolute top-0 left-0 right-0 bottom-0 flex justify-center items-center pointer-events-none"
             v-loading="!state.error && state.isLoading" element-loading-background="#0000">
            <p v-if="videoRef?.ended" class="error-panel shadow-lg shadow-[#0003] text-white">视频已结束</p>
        </div>
        <div class="absolute left-2 top-2 max-w-[61%]">
            <transition name="slide-fade-left">
                <div v-show="state.error" class="flex error-panel justify-between shadow-lg shadow-[#0003]" row wrap
                     inline>
                    <span class="text-white">{{ state.error && state.error.message }}</span>
                    <a class="ml-4 text-[#01C2FF] hover:text-gray-300 flex-none" @click.stop="play">重试</a>
                </div>
            </transition>
        </div>
        <div v-if="title" class="title">{{ title }}</div>
    </div>
</template>

<script setup lang="ts">
import { computed, onUnmounted, reactive, ref } from 'vue';
import { FLVPlayer } from './FLVPlayer'

const props = defineProps<{
    src?: string,
    title?: string,
    controls?: boolean,
    muted?: boolean,
    live?: boolean
}>()

const srcWithoutProtocol = computed(() => {
    return props.src?.replace(/^https?:/, '')
})

const videoRef = ref<HTMLVideoElement>()
let player: FLVPlayer | undefined
const state = reactive({
    isLoading: false,
    error: null as MediaError | null
})

function log(e: Event) {
    if (e.type == 'timeupdate') {
        return;
    }
    switch (e.type) {
        case 'canplaythrough':
        case 'playing':
            state.error = null
        case 'ended':
            state.isLoading = false;
            break
        case 'waiting':
            state.isLoading = true;
            break;
        case 'error':
            state.error = (e as ErrorEvent).error;
            break;
        default:
            break;
    }
}

async function play(src?: string) {
    if (player) {
        player.destroy();
    }
    player = new FLVPlayer(videoRef.value!, {
        type: 'flv',
        url: (src ?? props.src)?.replace(/^https?:/, ''),
        isLive: props.live,
        hasAudio: false
    }, { autoForward: props.live ?? false });
    // player.onerror = (error) => state.error = error;
    await player.load();
    player!.play()
}

function stop() {
    console.log('stop')
    player?.pause();
}

onUnmounted(() => {
    videoRef.value?.pause()
    player?.destroy()
})

defineExpose({
    play, stop
})

</script>

<style scoped>
.hls-video {
    position: relative;
    background-color: #0004;
    background-image: url(./assets/image.png);
    background-size: 100% 100%;
}

video {
    height: 100%;
    width: 100%;
    object-fit: fill;
}

.title {
    padding-left: 16px;
    position: absolute;
    left: 0;
    right: 0;
    bottom: 0;
    height: 32px;
    background: rgba(0, 0, 0, 0.6);
    font-size: 16px;
    line-height: 32px;
    /* identical to box height, or 125% */

    font-feature-settings: 'tnum' on, 'lnum' on;

    color: #E0F7FF;

    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.error-panel {
    padding: 16px;
    border-radius: 4px;
    background: #222;
}

:deep(.el-loading-spinner .path) {
    stroke: #E0F7FF;
}
</style>